package top.someapp.applib.webview;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Build;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.CookieManager;
import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import java.util.Locale;
import java.util.Map;
import top.someapp.applib.Base;
import top.someapp.applib.json.JsonHelper;
import top.someapp.applib.kits.Strings;

/**
 * Created by lejard_h on 20/12/2017.
 */
public class WebViewManager {

    private final WebViewExt webView;
    final Activity activity;
    final BrowserClient webViewClient;
    private WebViewCall.JavascriptChannel jsChannel;

    public WebViewManager(@NonNull final Activity activity) {
        this.webView = new WebViewExt(activity);
        this.activity = activity;
        webViewClient = new BrowserClient();
        init();
    }

    public WebViewManager(@NonNull final Activity activity, @NonNull final WebViewExt webView) {
        this.activity = activity;
        this.webView = webView;
        webViewClient = new BrowserClient();
        init();
    }

    private void init() {
        webView.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
                    if (webView.canGoBack()) {
                        webView.goBack();
                    } else {
                        activity.onBackPressed();
                    }
                    return true;
                }
                return false;
            }
        });

        webView.setWebViewClient(webViewClient);
        webView.setWebChromeClient(new WebChromeClient() {
        });

        // add a jsbridge
        webView.addJavascriptInterface(this, WebViewCall.JS_BRIDGE_OBJECT);
        // handle long click
        webView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                return true;
            }
        });
    }

    public WebViewExt getWebView() {
        return webView;
    }

    @SuppressLint("StaticFieldLeak")
    @JavascriptInterface
    public void postMessage(final long callbackId, final String action, final String args) {
        if (jsChannel == null) {
            return;
        }

        Object arguments = args;
        if (args != null && args.length() >= 2) { // maybe args is a json string
            arguments = JsonHelper.INSTANCE.toMap(args);
        }
        WebViewCall.CallbackResult result = new CallbackResultImpl(callbackId, action);
        int index = action.lastIndexOf('.');
        if (index > 0) {
            Base.MethodCallInfo methodCall = new JSMethodCall(action.substring(0, index),
                action.substring(index + 1), arguments);
            jsChannel.postMessage(methodCall, result);
        } else {
            Base.MethodCallInfo methodCall = new JSMethodCall(action, arguments);
            jsChannel.postMessage(methodCall, result);
        }
    }

    void evalJavascript(final String script) {
        webView.post(new Runnable() {
            @Override
            public void run() {
                webView.evaluateJavascript(script, new ValueCallback<String>() {
                    @Override
                    public void onReceiveValue(String value) {
                    }
                });
            }
        });
    }

    public WebViewCall.JavascriptChannel getJsChannel() {
        return jsChannel;
    }

    public void setJsChannel(WebViewCall.JavascriptChannel jsChannel) {
        this.jsChannel = jsChannel;
    }

    private void clearCookies() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            CookieManager.getInstance().removeAllCookies(new ValueCallback<Boolean>() {
                @Override
                public void onReceiveValue(Boolean value) {
                }
            });
        } else {
            CookieManager.getInstance().removeAllCookie();
        }
    }

    private void clearCache() {
        webView.clearCache(true);
        webView.clearFormData();
    }

    void loadUrl(
        boolean clearCache,
        boolean clearCookies,
        String userAgent,
        String url,
        Map<String, String> headers,
        boolean useScrollBar
    ) {
        if (clearCache) {
            clearCache();
        }
        if (clearCookies) {
            clearCookies();
        }

        if (userAgent != null) {
            webView.getSettings().setUserAgentString(userAgent);
        }
        webView.setUseScrollBar(useScrollBar);
        if (headers != null) {
            webView.loadUrl(url, headers);
        } else {
            webView.loadUrl(url);
        }
    }

    public void reload() {
        webView.post(new Runnable() {
            @Override
            public void run() {
                webView.reload();
            }
        });
    }

    void reloadUrl(String url) {
        webView.loadUrl(url);
    }

    void reloadUrl(String url, Map<String, String> headers) {
        webView.loadUrl(url, headers);
    }

    /**
     * Navigates forward on the Webview.
     */
//    void forward(MethodCall call, MethodChannel.Result result) {
//        if (webView != null && webView.canGoForward()) {
//            webView.goForward();
//        }
//    }

    void resize(FrameLayout.LayoutParams params) {
        webView.setLayoutParams(params);
    }

    /**
     * Reloads the Webview.
     */
    /// -------------------------------------------------------------------------------------------- add flutter.jar later
//    void reload(MethodCall call, MethodChannel.Result result) {
//        if (webView != null) {
//            webView.reload();
//        }
//    }

    /**
     * Navigates back on the Webview.
     */
//    void back(MethodCall call, MethodChannel.Result result) {
//        if (webView != null && webView.canGoBack()) {
//            webView.goBack();
//        }
//    }

    /**
     * Checks if going back on the Webview is possible.
     */
    boolean canGoBack() {
        return webView.canGoBack();
    }

    /**
     * Checks if going forward on the Webview is possible.
     */
    boolean canGoForward() {
        return webView.canGoForward();
    }

    class CallbackResultImpl implements WebViewCall.CallbackResult {

        public final String action;
        public final long callbackId;

        CallbackResultImpl(long callbackId, String action) {
            this.action = action;
            this.callbackId = callbackId;
        }

        @Override
        public void success(Object any) {
            if (callbackId != WebViewCall.VOID_JS_CALLBACK_ID) {
//                jsbridge.success = function (callbackId, result)
                String script = String.format(Locale.US, "%s.success(%s, %s)",
                    WebViewCall.JS_BRIDGE_OBJECT, String.valueOf(callbackId), String.valueOf(any));
                evalJavascript(script);
            }
        }

        @Override
        public void error(String code, String reason, Object other) {
            if (callbackId != WebViewCall.VOID_JS_CALLBACK_ID) {
//                jsbridge.error = function (callbackId, code, reason, other)
                if (Strings.isNotVisible(reason)) {
                    reason = "null";
                } else {
                    if (reason.contains("\"")) {
                        reason = reason.replaceAll("[\"]", "`");
                    }
                    reason = "\"" + reason + "\"";
                }
                String script = String.format(Locale.US, "%s.error(%s, %s, %s, %s)",
                    WebViewCall.JS_BRIDGE_OBJECT,
                    String.valueOf(callbackId),
                    String.valueOf(code),
                    reason,
                    String.valueOf(other));
                evalJavascript(script);
            }
        }

    }

//    void stopLoading(MethodCall call, MethodChannel.Result result) {
//        if (webView != null) {
//            webView.stopLoading();
//        }
//    }
    /// -------------------------------------------------------------------------------------------- ~add flutter.jar later
}
